class Method:
    def __init__(self, datas=[], q=0, *waste1, **waste2):
        """
            function : 初始化
            data     : 格式 [方案：属性值]
            q        : 区间值冠以正交
        """
        if not len(datas):
            self.data = [
                [([0.5, 0.5, 0.5], [0.5, 0.5, 0.5]),
                 ([0.2831, 0.3339, 0.3867], [0.2627, 0.3092, 0.3531]),
                 ([0.2708, 0.2957, 0.3132], [0.3071, 0.3258, 0.3387]),
                 ([0.3719, 0.3978, 0.4268], [0.2921, 0.3141, 0.3578])],

                [([0.3761, 0.4344, 0.4937], [0.3599, 0.4079, 0.4572]),
                 ([0.5, 0.5, 0.5], [0.5, 0.5, 0.5]),
                 ([0.4513, 0.4917, 0.5332], [0.2646, 0.3212, 0.3815]),
                 ([0.5811, 0.6215, 0.6629], [0.2721, 0.2997, 0.3254])],

                [([0.3667, 0.3998, 0.4329], [0.3765, 0.4195, 0.4631]),
                 ([0.2541, 0.3119, 0.3754], [0.4821, 0.5208, 0.5606]),
                 ([0.5, 0.5, 0.5], [0.5, 0.5, 0.5]),
                 ([0.4048, 0.4511, 0.5595], [0.2765, 0.3166, 0.3588])],

                [([0.2677, 0.3006, 0.3336], [0.3413, 0.3919, 0.4451]),
                 ([0.2721, 0.2997, 0.3254], [0.5811, 0.6215, 0.6629]),
                 ([0.2765, 0.3166, 0.3588], [0.4048, 0.4511, 0.5006]),
                 ([0.5, 0.5, 0.5], [0.5, 0.5, 0.5])]
            ]
        else:
            self.data = datas

        if q < 1:
            self.q = 2
        else:
            self.q = q

        self.ifshowProcess = 1
        pass

    def getResult(self):
        return []

# 使用 广义正交犹豫 拆分 广义正交直觉 加 可能度
class Method_Split_PD(Method):
    def splitToIFS(self, matrix=[], q=0):
        if not len(matrix):
            matrix = self.data
        if q < 1:
            q = self.q

        # 设定一些初始值
        m = len(matrix)            # 行
        n = len(matrix[0])         # 列数
        k = len(matrix[0][0])      # 每个模糊数据包括的信息个数
        l = len(matrix[0][0][0])   # 隶属度 u 的个数 和 非隶属度 v 的个数

        split_array = []
        for y in range(l):
            split_array.append([])
            for i in range(m):
                split_array[y].append([])
                for j in range(n):
                    split_array[y][i].append([])
                    for x in range(k):
                        split_array[y][i][j].append(matrix[i][j][x][y])
        return split_array

    def getResult(self):
        split_array = self.splitToIFS()
        q = self.q

        p_list = []
        for index, array in enumerate(split_array):
            if self.ifshowProcess:
                print("Process array {:}:".format(index))
            ifsmethod = QROIFSPRTEST(array, q)
            ifsmethod.ifshowprocess = self.ifshowProcess
            p = ifsmethod.get_priorityWeight()
            p_list.append(p)
            print(p)

        if self.ifshowProcess:
            print("拆分后的矩阵的可能度矩阵:")
            for p_i, p in enumerate(p_list):
                print("array {:}:\n{:}".format(p_i, p))

        result = [[p_list[i][j] for i in range(len(p_list))] for j in range(len(p_list[0]))]
        result = [sum(re) for re in result]
        if self.ifshowProcess:
            print("Score:\n", result)

        result = [re/sum(result) for re in result]
        return result

class QROIFSPRTEST:
    def __init__(self, data_array=[], q=2, *waste1, **waste2):
        """
            fucntion   : 初始化类
            data_array : 数据（矩阵形式）
            q          : 广义正交 使用的 参数
        """
        # 初始化数据data 和 q
        if not len(data_array):
            self.data_array = [
                [[2**(-1/q), 2**(-1/q)], [0.6, 0.5], [0.6, 0.7]],
                [[0.5, 0.6], [2**(-1/q), 2**(-1/q)], [0.7, 0.9]],
                [[0.7, 0.6], [0.9, 0.7], [2**(-1/q), 2**(-1/q)]]
            ]
        else:
            self.data_array = data_array

        self.q = q
        self.ifshowprocess = 1

        # 定义数据的行数、列数、每个元素组成个数
        self.array_row = len(self.data_array)
        self.array_col = len(self.data_array[0])
        self.array_ele = len(self.data_array[0][0])

    def get_priorityWeight(self, *waste1, **waste2):

        from scipy.optimize import minimize
        import numpy as np
        from math import fabs

        data = self.data_array
        q = self.q
        m = self.array_row      # m = n
        n = self.array_col
        k = self.array_ele

        w_num = 2
        w_total = w_num * n
        theta_num = k
        theta_total = theta_num * n * n
        zeta_num = k
        zeta_total = theta_num * n * n

        # x = [(w-, w+), (theta-, theta+), (zeta-. zeta+)]
        def objf(x):
            sum = 0
            for i in range(n-1):
                for j in range(i+1, n):
                    sum += x[w_total + n * theta_num * i + j * theta_num + 1]                # theta+
                    sum += x[w_total + n * theta_num * i + j * theta_num]                    # theta-
                    sum += x[w_total + theta_total + n * zeta_num * i + j * zeta_num + 1]  # zeta+
                    sum += x[w_total + theta_total + n * zeta_num * i + j * zeta_num]      # zeta-
            return sum

        def constraint1(x):
            con_list = []
            for i in range(n-1):
                for j in range(i+1, n):
                    con_list.append(
                        x[i * w_num] - x[j * w_num + 1] + 1 -
                        (data[i][j][0] - data[i][j][1] + data[i][j][0] ** q + data[i][j][1]**q) -
                        x[w_total + n * theta_num * i + j * theta_num + 1] +
                        x[w_total + n * theta_num * i + j * theta_num]
                    )
                    # print("i={:}, j={:}, u={:}, v={:}".format(i, j, data[i][j][0], data[i][j][1]))
            return con_list

        def constraint2(x):
            con_list = []
            for i in range(n-1):
                for j in range(i+1, n):
                    con_list.append(
                        x[j * w_num] - x[i * w_num + 1] + 1 -
                        (data[i][j][1] - data[i][j][0] + data[i][j][0] ** q + data[i][j][1]**q) -
                        x[w_total + theta_total + n * zeta_num * i + j * zeta_num + 1] +
                        x[w_total + theta_total + n * zeta_num * i + j * zeta_num]
                    )
            return con_list

        def constraint3(x):
            con_list = []
            for i in range(n):
                w_i_l = x[i * w_num]
                sum_w_j_u = sum([x[j * w_num + 1] for j in range(n) if j != i])
                con_list.append(w_i_l + sum_w_j_u - 1)
            return con_list

        def constraint4(x):
            con_list = []
            for i in range(n):
                w_i_u = x[i * w_num + 1]
                sum_w_j_l = sum([x[j * w_num] for j in range(n) if j != i])
                con_list.append(1 - w_i_u - sum_w_j_l)
            return con_list
        def constraint5(x):
            con_list = []
            for i in range(n):
                w_i_l = x[i * w_num]
                w_i_u = x[i * w_num + 1]
                con_list.append(w_i_u - w_i_l)
            return con_list


        cons = ([
            {'type': 'eq', 'fun': constraint1},
            {'type': 'eq', 'fun': constraint2},
            {'type': 'ineq', 'fun': constraint3},
            {'type': 'ineq', 'fun': constraint4},
            {'type': 'ineq', 'fun': constraint5}
        ])

        x0 = np.zeros([w_total + theta_total + zeta_total])  # 定义搜索的初值
        bnds = [(0, np.PINF) for i in range(w_total + theta_total + zeta_total)]
        # bnds = [(0, 1) for i in range(w_total)] + [(0, np.PINF) for i in range(theta_total + zeta_total)]

        res = minimize(objf, x0, method='SLSQP', bounds=bnds, constraints=cons,options={'maxiter': 1000, 'disp': False})
        w = res.x[:w_total]
        w = [[w[w_i], w[w_i+1]] for w_i in range(0, len(w)-1, 2)]
        theta = res.x[w_total:w_total+theta_total]
        zeta = res.x[w_total+theta_total:w_total+theta_total+zeta_total]
        w_tranfor = [[w[w_i][0], (1 - w[w_i][1]**q)**(1/q)] for w_i in range(len(w))]
        s = [w[0]**q - w[1]**q for w in w_tranfor]
        s_sort = sorted([[score, s_i] for s_i, score in enumerate(s)], key=lambda x: x[0], reverse=True)

        possible = lambda wi, wj: max(1 - max((wj[1] - wi[0])/(wj[1] - wj[0] + wi[1] - wi[0]), 0), 0)
        p = [[possible(w[i], w[j]) for j in range(len(w))] for i in range(len(w))]
        p_sum = [sum(item) for item in p]
        p_sort = sorted([[sum(item), index] for index, item in enumerate(p)], key=lambda x:x[0], reverse=True)

        if self.ifshowprocess:
            print(res)
            print("{:}\n{:}\n{:}".format(w, theta, zeta))
            print("min F = ", sum(theta+zeta))
            print("w = \n", w)
            print("w' = \n", w_tranfor)
            print('s = \n', s)
            print("s_sort = \n", s_sort)
            # print(("p = \n" + "{:}"*len(p)).format(*p))
            print("p = \n", p)
            print("p的累加 = \n", p_sum)
            print("p_sort = \n", p_sort)

        # return
        return p_sum

# 使用 广义正交犹豫 拆分 广义正交直觉 加 得分函数
class Method_Split_Score(Method):
    def splitToIFS(self, matrix=[], q=0):
        if not len(matrix):
            matrix = self.data
        if q < 1:
            q = self.q

        # 设定一些初始值
        m = len(matrix)  # 行
        n = len(matrix[0])  # 列数
        k = len(matrix[0][0])  # 每个模糊数据包括的信息个数
        l = len(matrix[0][0][0])  # 隶属度 u 的个数 和 非隶属度 v 的个数

        split_array = []
        for y in range(l):
            split_array.append([])
            for i in range(m):
                split_array[y].append([])
                for j in range(n):
                    split_array[y][i].append([])
                    for x in range(k):
                        split_array[y][i][j].append(matrix[i][j][x][y])
        return split_array

    def get_priorityWeight(self, data_array_IFS, q, *waste1, **waste2):

        from scipy.optimize import minimize
        import numpy as np
        from math import fabs

        data = data_array_IFS
        q = q
        m = len(data)
        n = len(data)
        k = len(data)

        w_num = 2
        w_total = w_num * n
        theta_num = k
        theta_total = theta_num * n * n
        zeta_num = k
        zeta_total = theta_num * n * n

        # x = [(w-, w+), (theta-, theta+), (zeta-. zeta+)]
        def objf(x):
            sum = 0
            for i in range(n - 1):
                for j in range(i + 1, n):
                    sum += x[w_total + n * theta_num * i + j * theta_num + 1]  # theta+
                    sum += x[w_total + n * theta_num * i + j * theta_num]  # theta-
                    sum += x[w_total + theta_total + n * zeta_num * i + j * zeta_num + 1]  # zeta+
                    sum += x[w_total + theta_total + n * zeta_num * i + j * zeta_num]  # zeta-
            return sum

        def constraint1(x):
            con_list = []
            for i in range(n - 1):
                for j in range(i + 1, n):
                    con_list.append(
                        x[i * w_num] - x[j * w_num + 1] + 1 -
                        (data[i][j][0] - data[i][j][1] + data[i][j][0] ** q + data[i][j][1] ** q) -
                        x[w_total + n * theta_num * i + j * theta_num + 1] +
                        x[w_total + n * theta_num * i + j * theta_num]
                    )
                    # print("i={:}, j={:}, u={:}, v={:}".format(i, j, data[i][j][0], data[i][j][1]))
            return con_list

        def constraint2(x):
            con_list = []
            for i in range(n - 1):
                for j in range(i + 1, n):
                    con_list.append(
                        x[j * w_num] - x[i * w_num + 1] + 1 -
                        (data[i][j][1] - data[i][j][0] + data[i][j][0] ** q + data[i][j][1] ** q) -
                        x[w_total + theta_total + n * zeta_num * i + j * zeta_num + 1] +
                        x[w_total + theta_total + n * zeta_num * i + j * zeta_num]
                    )
            return con_list

        def constraint3(x):
            con_list = []
            for i in range(n):
                w_i_l = x[i * w_num]
                sum_w_j_u = sum([x[j * w_num + 1] for j in range(n) if j != i])
                con_list.append(w_i_l + sum_w_j_u - 1)
            return con_list

        def constraint4(x):
            con_list = []
            for i in range(n):
                w_i_u = x[i * w_num + 1]
                sum_w_j_l = sum([x[j * w_num] for j in range(n) if j != i])
                con_list.append(1 - w_i_u - sum_w_j_l)
            return con_list

        def constraint5(x):
            con_list = []
            for i in range(n):
                w_i_l = x[i * w_num]
                w_i_u = x[i * w_num + 1]
                con_list.append(w_i_u - w_i_l)
            return con_list

        cons = ([
            {'type': 'eq', 'fun': constraint1},
            {'type': 'eq', 'fun': constraint2},
            {'type': 'ineq', 'fun': constraint3},
            {'type': 'ineq', 'fun': constraint4},
            {'type': 'ineq', 'fun': constraint5}
        ])

        x0 = np.zeros([w_total + theta_total + zeta_total])  # 定义搜索的初值
        bnds = [(0, 1) for i in range(w_total)] + [(0, np.PINF) for i in range(theta_total + zeta_total)]

        res = minimize(objf, x0, method='SLSQP', bounds=bnds, constraints=cons,
                       options={'maxiter': 1000, 'disp': False})

        w = res.x[:w_total]  # 提取 w = [w-, w+]
        w = [[w[w_i], w[w_i + 1]] for w_i in range(0, len(w) - 1, 2)]

        theta = res.x[w_total:w_total + theta_total]
        zeta = res.x[w_total + theta_total:w_total + theta_total + zeta_total]

        w_tranfor = [[w[w_i][0], (1 - w[w_i][1] ** q) ** (1 / q)] for w_i in range(len(w))]  # 将 w 转换 ！!
        # s = [w[0]**q - w[1]**q for w in w_tranfor]
        # s_sort = sorted([[score, s_i] for s_i, score in enumerate(s)], key=lambda x: x[0], reverse=True)

        if self.ifshowProcess:
            print(res)
            print("{:}\n{:}\n{:}".format(w, theta, zeta))
            print("min F = ", sum(theta + zeta))
            print("w = \n", w)
            print("w' = \n", w_tranfor)
            # print('s = \n', s)
            # print("s_sort = \n", s_sort)

        # return
        return w_tranfor

    def getResult(self):
        split_array = self.splitToIFS()
        q = self.q

        w_list = []
        for index, array in enumerate(split_array):
            if self.ifshowProcess:
                print("Process array {:}:".format(index))
            w = self.get_priorityWeight(array, q)
            w_list.append(w)
            if self.ifshowProcess:
                print("W of array {:}: {:}".format(index + 1, w))

        if self.ifshowProcess:
            print("拆分后的 w 分别是: ", )
            for w in w_list:
                print(w)

        w_aggregate = []
        for w_j in range(len(w_list[0])):
            u_list = []
            v_list = []
            for w_i in range(len(w_list)):
                u_list.append(w_list[w_i][w_j][0])
                v_list.append(w_list[w_i][w_j][1])
            w_aggregate.append((u_list, v_list))

        if self.ifshowProcess:
            print("集结后的 w :")
            for w in w_aggregate:
                print(w)

        scorefunc = lambda d: 1 / len(d[0]) * sum([u ** q for u in d[0]]) - \
                              1 / len(d[1]) * sum([v ** q for v in d[1]])
        score_list = [scorefunc(w) for w in w_aggregate]
        if self.ifshowProcess:
            print("最终得分:", score_list)

        return score_list
        # return [-s/sum(score_list) for s in score_list]

        # if self.ifshowProcess:
        #     print("拆分后的矩阵的得分:")
        #     for s_i, s in enumerate(s_list):
        #         print("array {:}:\n{:}".format(s_i, s))

        # result = [[s_list[i][j] for i in range(len(s_list))] for j in range(len(s_list[0]))]
        # result = [sum(re) for re in result]
        # if self.ifshowProcess:
        #     print("加总后的 Score:\n", result)
        #
        # result = [re/sum(result) for re in result]
        # return result


# 广义正交犹豫模糊偏好关系 有 β 和 α（但没限制0or1） 且 theta 和 zeta 个数为 1
# (0.5（wiu^ q + wjv^q）) ^ 1/q
class ROHFPRTEST(Method):
    def getResult(self, data=[], q=0):
        import numpy as np
        from scipy.optimize import minimize
        import math

        if not len(data):
            data = self.data
        if q < 1:
            q = self.q

        # 设定一些初始值
        m = len(data)  # 行    m == n
        n = len(data[0])  # 列数
        k = len(data[0][0])  # 每个模糊数据包括的信息个数
        l = len(data[0][0][0])  # 隶属度 u 的个数 和 非隶属度 v 的个数

        # x = [ [w:2] [theta:1] [zeta:1] [alpha:3] [beta:3]]
        w_num = 2  # 每个 w = [w-, w+]
        w_total = w_num * n
        theta_num = 1  # 每个 theta 对应 u = [theta1, theta2, theta3]
        theta_total = m * n * theta_num
        zeta_num = 1
        zeta_total = m * n * zeta_num

        # 有 β 和 α
        alpha_num = l
        alpha_total = m * n * alpha_num

        beta_num = l
        beta_total = m * n * beta_num

        x0 = np.zeros([w_total + theta_total + zeta_total + alpha_total + beta_total])  # 定义搜索的初值
        bnds = [(0, 1) for i in range(w_total)] + \
               [(np.NINF, np.PINF) for i in range(theta_total + zeta_total)] + \
               [(0, 1) for i in range(alpha_total + beta_total)]

        def objf(x):
            """
                目标函数
            """
            sum = 0
            for i in range(m - 1):
                for j in range(i + 1, n):
                    sum += math.fabs(x[w_total + n * theta_num * i + theta_num * j])
                    sum += math.fabs(x[w_total + theta_total + n * zeta_num * i + zeta_num * j])
            return sum

        def constraint1(x):
            """
                wu 相关
            """
            con_list = []
            for i in range(m - 1):
                for j in range(i + 1, n):
                    if i != j:
                        con_list.append(
                            x[w_total + n * theta_num * i + theta_num * j] -
                            sum([data[i][j][0][s] * x[
                                w_total + theta_total + zeta_total + n * alpha_num * i + alpha_num * j + s] for s in
                                 range(l)]) +
                            ((x[i * w_num] ** q + x[j * w_num] ** q + 1) * 0.5) ** (1 / q)
                        )

            return con_list

        def constraint2(x):
            """
                wv 相关
            """
            con_list = []
            for i in range(m - 1):
                for j in range(i + 1, n):
                    if i != j:
                        con_list.append(
                            x[w_total + theta_total + n * zeta_num * i + zeta_num * j] -
                            sum([data[i][j][1][s] * x[
                                w_total + theta_total + zeta_total + alpha_total + n * beta_num * i + beta_num * j + s]
                                 for s in range(l)]) +
                            ((x[i * w_num + 1] ** q + x[j * w_num] ** q) * 0.5) ** (1 / q)
                        )
            return con_list

        def constraint3(x):
            """
                wuq + wvq <= 1
            """
            con_list = []
            for i in range(m):
                con_list.append(1 - x[i * w_num] ** q - x[i * w_num + 1] ** q)
            return con_list

        def constraint4(x):
            """
                wvi^q - wuj^q累加 >= 0
            """
            con_list = []
            for i in range(n):
                w_i_v = x[i * w_num + 1] ** q
                sum_w_j_u = sum([x[j * w_num] ** q for j in range(n) if j != i])
                con_list.append(w_i_v - sum_w_j_u)
            return con_list

        def constraint5(x):
            con_list = []
            for i in range(n):
                w_i_u = x[i * w_num] ** q
                sum_w_j_v = sum([x[j * w_num + 1] ** q for j in range(n) if j != i])
                con_list.append(w_i_u + n - 2 - sum_w_j_v)
            return con_list

        def constraint6(x):
            con_list = []
            for i in range(m):
                for j in range(n):
                    sum_a = 0
                    sum_b = 0
                    for s in range(l):
                        a = x[w_total + theta_total + zeta_total + n * alpha_num * i + alpha_num * j + s]
                        b = x[w_total + theta_total + zeta_total + alpha_total + n * beta_num * i + beta_num * j + s]
                        # con_list.append(a * (a - 1))
                        # con_list.append(b * (b - 1))
                        sum_a += a
                        sum_b += b
                    con_list.append(sum_a - 1)
                    con_list.append(sum_b - 1)
            return con_list

        cons = ([
            {'type': 'eq', 'fun': constraint1},
            {'type': 'eq', 'fun': constraint2},
            {'type': 'ineq', 'fun': constraint3},
            {'type': 'ineq', 'fun': constraint4},
            {'type': 'ineq', 'fun': constraint5},
            {'type': 'eq', 'fun': constraint6}
        ])

        res = minimize(objf, x0, method='SLSQP', bounds=bnds, constraints=cons,
                       options={'maxiter': 1000, 'disp': False})

        w = res.x[:w_total]
        w = [[w[w_i], w[w_i + 1]] for w_i in range(0, len(w) - 1, 2)]

        theta = res.x[w_total: w_total + theta_total]
        zeta = res.x[w_total + theta_total: w_total + theta_total + zeta_total]
        alpha = res.x[w_total + theta_total + zeta_total: w_total + theta_total + zeta_total + alpha_total]
        beta = res.x[
               w_total + theta_total + zeta_total + alpha_total: w_total + theta_total + zeta_total + alpha_total + beta_total]

        w_tranfor = [[w[w_i][0], (1 - w[w_i][1] ** q) ** (1 / q)] for w_i in range(len(w))]

        s = [(weight[0] ** q - weight[1] ** q + 1) / 2 for weight in w_tranfor]
        s_norm = [score / sum(s) for score in s]
        s_sort = sorted([[score, s_i] for s_i, score in enumerate(s_norm)], key=lambda x: x[0], reverse=True)

        if self.ifshowProcess:
            print(res)
            print("w:{:}\ntheta:{:}\nzeta:{:}\nalpha:{:}\nbeta:{:}\n".format(w, theta, zeta, alpha, beta))
            print("w = \n", w)
            print("w' = \n", w_tranfor)
            print("score = \n", s)
            print("normal score = \n", s_norm)
            print("s_sort = \n", s_sort)

        return s_norm

    pass


# 广义正交犹豫模糊偏好关系 无 β 和 α 且 theta 和 zeta 个数为 3
# (0.5（wiu^ q - wjv^q）) ^ 1/q
class ROHFPRTEST_MultiWeight2(Method):
    def getResult(self, data=[], q=0):
        import numpy as np
        from scipy.optimize import minimize
        import math

        if not len(data):
            data = self.data
        if q < 1:
            q = self.q

        # 设定一些初始值
        m = len(data)  # 行    m == n
        n = len(data[0])  # 列数
        k = len(data[0][0])  # 每个模糊数据包括的信息个数
        l = len(data[0][0][0])  # 隶属度 u 的个数 和 非隶属度 v 的个数

        print("mnkl", m, n, k, l)
        # x = [ [w:2] [theta:1] [zeta:1] [alpha:3] [beta:3]]
        w_num = l * k  # 每个 w = [w-, w+]
        w_total = w_num * n
        theta_num = l  # 每个 theta 对应 u = [theta1, theta2, theta3]
        theta_total = m * n * theta_num
        zeta_num = l
        zeta_total = m * n * zeta_num

        x0 = np.zeros([w_total + theta_total + zeta_total])  # 定义搜索的初值
        bnds = [(0, 1) for i in range(w_total)] + \
               [(np.NINF, np.PINF) for i in range(theta_total + zeta_total)]

        def objf(x):
            """
                目标函数
            """
            sum = 0
            for i in range(m - 1):
                for j in range(i + 1, n):
                    for s in range(l):
                        sum += math.fabs(x[w_total + n * theta_num * i + theta_num * j + s])
                        sum += math.fabs(x[w_total + theta_total + n * zeta_num * i + zeta_num * j + s])
            return sum

        def constraint1(x):
            """
                wu 相关
            """
            con_list = []
            for i in range(m - 1):
                for j in range(i + 1, n):
                    for s in range(l):
                        con_list.append(
                            x[w_total + n * theta_num * i + theta_num * j + s] -
                            data[i][j][0][s] +
                            (math.fabs((x[i * w_num + s] ** q - x[j * w_num + s] ** q) * 0.5)) ** (1 / q)
                        )

            return con_list

        def constraint2(x):
            """
                wv 相关
            """
            con_list = []
            for i in range(m - 1):
                for j in range(i + 1, n):
                    for s in range(l):
                        con_list.append(
                            x[w_total + theta_total + n * zeta_num * i + zeta_num * j + s] -
                            data[i][j][1][s] +
                            (math.fabs((x[i * w_num + l + s] ** q - x[j * w_num + l + s] ** q) * 0.5)) ** (1 / q)
                        )
            return con_list

        def constraint3(x):
            """
                wuq + wvq <= 1
            """
            con_list = []
            for i in range(m):
                for s in range(l):
                    con_list.append(1 - x[i * w_num + s] ** q - x[i * w_num + l + s] ** q)
            return con_list

        def constraint4(x):
            """
                wvi^q - wuj^q累加 >= 0
            """
            con_list = []
            for i in range(n):
                for s in range(l):
                    w_i_v = x[i * w_num + l + s] ** q
                    sum_w_j_u = sum([x[j * w_num + s] ** q for j in range(n) if j != i])
                    con_list.append(w_i_v - sum_w_j_u)
            return con_list

        def constraint5(x):
            """
                wui^q + n - 2 - wvj^q累加 >= 0
            """
            con_list = []
            for i in range(n):
                for s in range(l):
                    w_i_u = x[i * w_num + s] ** q
                    sum_w_j_v = sum([x[j * w_num + l + s] ** q for j in range(n) if j != i])
                    con_list.append(w_i_u + n - 2 - sum_w_j_v)
            return con_list

        cons = ([
            {'type': 'eq', 'fun': constraint1},
            {'type': 'eq', 'fun': constraint2},
            {'type': 'ineq', 'fun': constraint3},
            {'type': 'ineq', 'fun': constraint4},
            {'type': 'ineq', 'fun': constraint5},
        ])

        res = minimize(objf, x0, method='SLSQP', bounds=bnds, constraints=cons,
                       options={'maxiter': 1000, 'disp': False})

        w = res.x[:w_total]
        print(len(w))
        w = [[[w[w_i * w_num + s] for s in range(l)], [w[w_i * w_num + l + s] for s in range(l)]] for w_i in range(m)]

        theta = res.x[w_total: w_total + theta_total]
        zeta = res.x[w_total + theta_total: w_total + theta_total + zeta_total]

        s = [(1 / len(weight[0])) * sum([item ** q for item in weight[0]]) -
             (1 / len(weight[1])) * sum([item ** q for item in weight[1]]) for weight in w]
        s_norm = [score / sum(s) for score in s]
        s_sort = sorted([[score, s_i] for s_i, score in enumerate(s_norm)], key=lambda x: x[0], reverse=True)
        if self.ifshowProcess:
            print(res)
            print("w:{:}\ntheta:{:}\nzeta:{:}\n".format(w, theta, zeta))
            print("w = \n", w)
            print("w.len\n", len(w))
            print("score = \n", s)
            print("normal score = \n", s_norm)
            print("s_sort = \n", s_sort)

        return s_norm

    pass


# 广义正交犹豫模糊偏好关系 无 β 和 α 且 theta 和 zeta 个数为 3
# (0.5（wiu^ q + wjv^q）) ^ 1/q
class ROHFPRTEST_MultiWeight3(Method):
    def getResult(self, data=[], q=0):
        import numpy as np
        from scipy.optimize import minimize
        import math

        if not len(data):
            data = self.data
        if q < 1:
            q = self.q

        # 设定一些初始值
        m = len(data)  # 行    m == n
        n = len(data[0])  # 列数
        k = len(data[0][0])  # 每个模糊数据包括的信息个数
        l = len(data[0][0][0])  # 隶属度 u 的个数 和 非隶属度 v 的个数

        print("mnkl", m, n, k, l)
        # x = [ [w:2] [theta:1] [zeta:1] [alpha:3] [beta:3]]
        w_num = l * k  # 每个 w = [w-, w+]
        w_total = w_num * n
        theta_num = l  # 每个 theta 对应 u = [theta1, theta2, theta3]
        theta_total = m * n * theta_num
        zeta_num = l
        zeta_total = m * n * zeta_num

        x0 = np.zeros([w_total + theta_total + zeta_total])  # 定义搜索的初值
        bnds = [(0, 1) for i in range(w_total)] + \
               [(np.NINF, np.PINF) for i in range(theta_total + zeta_total)]

        def objf(x):
            """
                目标函数
            """
            sum = 0
            for i in range(m - 1):
                for j in range(i + 1, n):
                    for s in range(l):
                        sum += math.fabs(x[w_total + n * theta_num * i + theta_num * j + s])
                        sum += math.fabs(x[w_total + theta_total + n * zeta_num * i + zeta_num * j + s])
            return sum

        def constraint1(x):
            """
                wu 相关
            """
            con_list = []
            for i in range(m - 1):
                for j in range(i + 1, n):
                    for s in range(l):
                        con_list.append(
                            x[w_total + n * theta_num * i + theta_num * j + s] -
                            data[i][j][0][s] +
                            ((x[i * w_num + s] ** q + x[j * w_num + l + s] ** q) * 0.5) ** (1 / q)
                        )
            return con_list

        def constraint2(x):
            """
                wv 相关
            """
            con_list = []
            for i in range(m - 1):
                for j in range(i + 1, n):
                    for s in range(l):
                        con_list.append(
                            x[w_total + theta_total + n * zeta_num * i + zeta_num * j + s] -
                            data[i][j][1][s] +
                            ((x[i * w_num + l + s] ** q + x[j * w_num + s] ** q) * 0.5) ** (1 / q)
                        )
            return con_list

        def constraint3(x):
            """
                wuq + wvq <= 1
            """
            con_list = []
            for i in range(m):
                for s in range(l):
                    con_list.append(1 - x[i * w_num + s] ** q - x[i * w_num + l + s] ** q)
            return con_list

        def constraint4(x):
            """
                wvi^q - wuj^q累加 >= 0
            """
            con_list = []
            for i in range(n):
                for s in range(l):
                    w_i_v = x[i * w_num + l + s] ** q
                    sum_w_j_u = sum([x[j * w_num + s] ** q for j in range(n) if j != i])
                    con_list.append(w_i_v - sum_w_j_u)
            return con_list

        def constraint5(x):
            """
                wui^q + n - 2 - wvj^q累加 >= 0
            """
            con_list = []
            for i in range(n):
                for s in range(l):
                    w_i_u = x[i * w_num + s] ** q
                    sum_w_j_v = sum([x[j * w_num + l + s] ** q for j in range(n) if j != i])
                    con_list.append(w_i_u + n - 2 - sum_w_j_v)
            return con_list

        cons = ([
            {'type': 'eq', 'fun': constraint1},
            {'type': 'eq', 'fun': constraint2},
            {'type': 'ineq', 'fun': constraint3},
            {'type': 'ineq', 'fun': constraint4},
            {'type': 'ineq', 'fun': constraint5},
        ])

        res = minimize(objf, x0, method='SLSQP', bounds=bnds, constraints=cons,
                       options={'maxiter': 1000, 'disp': False})

        w = res.x[:w_total]
        print(len(w))
        w = [[[w[w_i * w_num + s] for s in range(l)], [w[w_i * w_num + l + s] for s in range(l)]] for w_i in range(m)]

        theta = res.x[w_total: w_total + theta_total]
        zeta = res.x[w_total + theta_total: w_total + theta_total + zeta_total]

        s = [(1 / len(weight[0])) * sum([item ** q for item in weight[0]]) -
             (1 / len(weight[1])) * sum([item ** q for item in weight[1]]) for weight in w]
        s_norm = [score / sum(s) for score in s]
        s_sort = sorted([[score, s_i] for s_i, score in enumerate(s_norm)], key=lambda x: x[0], reverse=True)
        if self.ifshowProcess:
            print(res)
            print("w:{:}\ntheta:{:}\nzeta:{:}\n".format(w, theta, zeta))
            print("w = \n", w)
            print("w.len\n", len(w))
            print("score = \n", s)
            print("normal score = \n", s_norm)
            print("s_sort = \n", s_sort)

        return s_norm

    pass


# 广义正交犹豫模糊偏好关系 无 β 和 α 且 theta 和 zeta 个数为 3
# (uijs - vijs + uijsq + vijsq)
class ROHFPRTEST_MultiWeight4(Method):
    """
        论文中模型 待测试 4
    """

    def getResult(self, data=[], q=0):

        import numpy as np
        from scipy.optimize import minimize
        import math

        if not len(data):
            data = self.data
        if q < 1:
            q = self.q

        # 设定一些初始值
        m = len(data)  # 行    m == n
        n = len(data[0])  # 列数
        k = len(data[0][0])  # 每个模糊数据包括的信息个数
        l = len(data[0][0][0])  # 隶属度 u 的个数 和 非隶属度 v 的个数

        print("mnkl", m, n, k, l)
        # x = [ [w:2] [theta:1] [zeta:1] [alpha:3] [beta:3]]
        w_num = l * k  # 每个 w = [w-, w+]
        w_total = w_num * n
        theta_num = l  # 每个 theta 对应 u = [theta1, theta2, theta3]
        theta_total = m * n * theta_num
        zeta_num = l
        zeta_total = m * n * zeta_num

        x0 = np.zeros([w_total + theta_total + zeta_total])  # 定义搜索的初值
        bnds = [(0, 1) for i in range(w_total)] + \
               [(np.NINF, np.PINF) for i in range(theta_total + zeta_total)]

        def objf(x):
            """
                目标函数
            """
            sum = 0
            for i in range(m - 1):
                for j in range(i + 1, n):
                    for s in range(l):
                        sum += math.fabs(x[w_total + n * theta_num * i + theta_num * j + s])
                        sum += math.fabs(x[w_total + theta_total + n * zeta_num * i + zeta_num * j + s])
            return sum

        def constraint1(x):
            """
                wu 相关
            """
            con_list = []
            for i in range(m - 1):
                for j in range(i + 1, n):
                    for s in range(l):
                        con_list.append(
                            x[w_total + n * theta_num * i + theta_num * j + s] -
                            x[i * w_num + s] + x[j * w_num + l + s] - 1 +
                            (data[i][j][0][s] - data[i][j][1][s] + data[i][j][0][s] ** q + data[i][j][1][s] ** q)
                        )
            return con_list

        def constraint2(x):
            """
                wv 相关
            """
            con_list = []
            for i in range(m - 1):
                for j in range(i + 1, n):
                    for s in range(l):
                        con_list.append(
                            x[w_total + theta_total + n * zeta_num * i + zeta_num * j + s] -
                            x[j * w_num + s] + x[i * w_num + l + s] - 1 +
                            (data[i][j][1][s] - data[i][j][0][s] + data[i][j][0][s] ** q + data[i][j][1][s] ** q)
                        )
            return con_list

        def constraint3(x):
            """
                wuq + wvq <= 1
            """
            con_list = []
            for i in range(m):
                for s in range(l):
                    con_list.append(1 - x[i * w_num + s] ** q - x[i * w_num + l + s] ** q)
            return con_list

        def constraint4(x):
            """
                1 - wvi^q - wuj^q累加 >= 0
            """
            con_list = []
            for i in range(n):
                for s in range(l):
                    w_i_v = x[i * w_num + l + s]
                    sum_w_j_u = sum([x[j * w_num + s] for j in range(n) if j != i])
                    con_list.append(1 - w_i_v - sum_w_j_u)
            return con_list

        def constraint5(x):
            """
                wui^q + n - 2 - wvj^q累加 >= 0
            """
            con_list = []
            for i in range(n):
                for s in range(l):
                    w_i_u = x[i * w_num + s]
                    sum_w_j_v = sum([x[j * w_num + l + s] for j in range(n) if j != i])
                    con_list.append(w_i_u + sum_w_j_v - 1)
            return con_list

        cons = ([
            {'type': 'ineq', 'fun': constraint3},
            {'type': 'ineq', 'fun': constraint4},
            {'type': 'ineq', 'fun': constraint5},
            {'type': 'eq', 'fun': constraint1},
            {'type': 'eq', 'fun': constraint2},
        ])

        res = minimize(objf, x0, method='SLSQP', bounds=bnds, constraints=cons,
                       options={'maxiter': 1000, 'disp': False})

        w = res.x[:w_total]
        print(len(w))
        w = [[[w[w_i * w_num + s] for s in range(l)], [w[w_i * w_num + l + s] for s in range(l)]] for w_i in range(m)]

        theta = res.x[w_total: w_total + theta_total]
        zeta = res.x[w_total + theta_total: w_total + theta_total + zeta_total]

        s = [(1 / len(weight[0])) * sum([item ** q for item in weight[0]]) -
             (1 / len(weight[1])) * sum([item ** q for item in weight[1]]) for weight in w]
        s_norm = [score / sum(s) for score in s]
        s_sort = sorted([[score, s_i] for s_i, score in enumerate(s_norm)], key=lambda x: x[0], reverse=True)

        if self.ifshowProcess:
            print(res)
            print("w:{:}\ntheta:{:}\nzeta:{:}\n".format(w, theta, zeta))
            print("w = \n", w)
            print("w.len\n", len(w))
            print("score = \n", s)
            print("normal score = \n", s_norm)
            print("s_sort = \n", s_sort)

        return s_norm

    pass


# 广义正交犹豫模糊偏好关系 有 β 和 α（没限制0/1) 且 theta 和 zeta 个数为 3
# (0.5（wiu^ q + wjv^q）) ^ 1/q
class ROHFPRTEST_MultiWeight5(Method):
    def getResult(self, data=[], q=0):
        import numpy as np
        from scipy.optimize import minimize
        import math

        if not len(data):
            data = self.data
        if q < 1:
            q = self.q

        # 设定一些初始值
        m = len(data)  # 行    m == n
        n = len(data[0])  # 列数
        k = len(data[0][0])  # 每个模糊数据包括的信息个数
        l = len(data[0][0][0])  # 隶属度 u 的个数 和 非隶属度 v 的个数

        # x = [ [w:2] [theta:1] [zeta:1] [alpha:3] [beta:3]]
        w_num = 2  # 每个 w = [w-, w+]
        w_total = w_num * n
        theta_num = l  # 每个 theta 对应 u = [theta1, theta2, theta3]
        theta_total = m * n * theta_num
        zeta_num = l
        zeta_total = m * n * zeta_num

        # 有 β 和 α
        alpha_num = l
        alpha_total = m * n * alpha_num

        beta_num = l
        beta_total = m * n * beta_num

        x0 = np.zeros([w_total + theta_total + zeta_total + alpha_total + beta_total])  # 定义搜索的初值
        bnds = [(0, 1) for i in range(w_total)] + \
               [(np.NINF, np.PINF) for i in range(theta_total + zeta_total)] + \
               [(0, 1) for i in range(alpha_total + beta_total)]

        def objf(x):
            """
                目标函数
            """
            sum = 0
            for i in range(m - 1):
                for j in range(i + 1, n):
                    for s in range(l):
                        sum += math.fabs(x[w_total + n * theta_num * i + theta_num * j + s])
                        sum += math.fabs(x[w_total + theta_total + n * zeta_num * i + zeta_num * j + s])
            return sum

        def constraint1(x):
            """
                wu 相关
            """
            con_list = []
            for i in range(m - 1):
                for j in range(i + 1, n):
                    for s in range(l):
                        con_list.append(
                            x[w_total + n * theta_num * i + theta_num * j + s] -
                            sum([data[i][j][0][s] * x[
                                w_total + theta_total + zeta_total + n * alpha_num * i + alpha_num * j + s] for s in
                                 range(l)]) +
                            ((x[i * w_num] ** q + x[j * w_num] ** q + 1) * 0.5) ** (1 / q)
                        )

            return con_list

        def constraint2(x):
            """
                wv 相关
            """
            con_list = []
            for i in range(m - 1):
                for j in range(i + 1, n):
                    if i != j:
                        con_list.append(
                            x[w_total + theta_total + n * zeta_num * i + zeta_num * j] -
                            sum([data[i][j][1][s] * x[
                                w_total + theta_total + zeta_total + alpha_total + n * beta_num * i + beta_num * j + s]
                                 for s in range(l)]) +
                            ((x[i * w_num + 1] ** q + x[j * w_num] ** q) * 0.5) ** (1 / q)
                        )
            return con_list

        def constraint3(x):
            """
                wuq + wvq <= 1
            """
            con_list = []
            for i in range(m):
                con_list.append(1 - x[i * w_num] ** q - x[i * w_num + 1] ** q)
            return con_list

        def constraint4(x):
            """
                wvi^q - wuj^q累加 >= 0
            """
            con_list = []
            for i in range(n):
                w_i_v = x[i * w_num + 1] ** q
                sum_w_j_u = sum([x[j * w_num] ** q for j in range(n) if j != i])
                con_list.append(w_i_v - sum_w_j_u)
            return con_list

        def constraint5(x):
            con_list = []
            for i in range(n):
                w_i_u = x[i * w_num] ** q
                sum_w_j_v = sum([x[j * w_num + 1] ** q for j in range(n) if j != i])
                con_list.append(w_i_u + n - 2 - sum_w_j_v)
            return con_list

        def constraint6(x):
            con_list = []
            for i in range(m):
                for j in range(n):
                    sum_a = 0
                    sum_b = 0
                    for s in range(l):
                        a = x[w_total + theta_total + zeta_total + n * alpha_num * i + alpha_num * j + s]
                        b = x[w_total + theta_total + zeta_total + alpha_total + n * beta_num * i + beta_num * j + s]
                        # con_list.append(a * (a - 1))
                        # con_list.append(b * (b - 1))
                        sum_a += a
                        sum_b += b
                    con_list.append(sum_a - 1)
                    con_list.append(sum_b - 1)
            return con_list

        cons = ([
            {'type': 'eq', 'fun': constraint1},
            {'type': 'eq', 'fun': constraint2},
            {'type': 'ineq', 'fun': constraint3},
            {'type': 'ineq', 'fun': constraint4},
            {'type': 'ineq', 'fun': constraint5},
            {'type': 'eq', 'fun': constraint6}
        ])

        res = minimize(objf, x0, method='SLSQP', bounds=bnds, constraints=cons,
                       options={'maxiter': 1000, 'disp': False})

        w = res.x[:w_total]
        w = [[w[w_i], w[w_i + 1]] for w_i in range(0, len(w) - 1, 2)]

        theta = res.x[w_total: w_total + theta_total]
        zeta = res.x[w_total + theta_total: w_total + theta_total + zeta_total]
        alpha = res.x[w_total + theta_total + zeta_total: w_total + theta_total + zeta_total + alpha_total]
        beta = res.x[
               w_total + theta_total + zeta_total + alpha_total: w_total + theta_total + zeta_total + alpha_total + beta_total]

        w_tranfor = [[w[w_i][0], (1 - w[w_i][1] ** q) ** (1 / q)] for w_i in range(len(w))]

        s = [(weight[0] ** q - weight[1] ** q + 1) / 2 for weight in w_tranfor]
        s_norm = [score / sum(s) for score in s]
        s_sort = sorted([[score, s_i] for s_i, score in enumerate(s_norm)], key=lambda x: x[0], reverse=True)

        if self.ifshowProcess:
            print(res)
            print("w:{:}\ntheta:{:}\nzeta:{:}\nalpha:{:}\nbeta:{:}\n".format(w, theta, zeta, alpha, beta))
            print("w = \n", w)
            print("w' = \n", w_tranfor)
            print("score = \n", s)
            print("normal score = \n", s_norm)
            print("s_sort = \n", s_sort)

        return s_norm

    pass


if __name__ == "__main__":
    data = [
        [[0.5000, 0.5000], [0.2850, 0.4450], [0.5413, 0.3213], [0.1878, 0.5778]],
        [[0.4450, 0.2850], [0.5000, 0.5000], [0.5881, 0.2081], [0.3776, 0.6076]],
        [[0.3213, 0.5413], [0.2081, 0.5881], [0.5000, 0.5000], [0.1428, 0.7528]],
        [[0.5778, 0.1878], [0.6076, 0.3776], [0.7528, 0.1428], [0.5000, 0.5000]]
    ]
    test = QROIFSPRTEST(q=2)
    test.get_priorityWeight()

    # st = SplitTry()
    # st.getResult()

    # test = SplitTryWithScore()
    # print(test.getResult())

